import { BSC } from '@/config/net';
import { Message } from 'element-ui';
import { chainIdMap } from './constants';

// 判断设备类型
export const detectDeviceType = () => (/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|OperaMini/i.test(navigator.userAgent) ? 'Mobile' : 'Desktop');

// 处理科学计数显示问题
export const toNonExponential = (num) => {
  const m = $big(num).toExponential().match(/\d(?:\.(\d*))?e([+-]\d+)/);
  return $big(num).toFixed(Math.max(0, (m[1] || '').length - m[2]), $big.ROUND_DOWN);
};

// 整数转小数
export const toDecimals = (amount, decimals) => toNonExponential($big(amount).div($big(10).pow($big(decimals))));

// 小数转整数
export const toInteger = (amount, decimals) => toNonExponential($big(amount).times($big(10).pow($big(decimals))));

// 获取当前账户
export const getCurrentAccount = async () => {
  if (!window.ethereum) return;
  const requestInfo = await ethereum.request({ method: 'eth_accounts' });
  return requestInfo[0];
};

/**
 * 保留小数
 * @param amount
 * @param fix
 * @returns {number}
 */
export const toFixed = (amount = 0, fix = 6) => Number(String(amount).match(new RegExp(`^\\d+(?:\\.\\d{0,${fix}})?`)) || 0);

/**
 * 切换链
 * @param target：切换到目标链名称，如，HECO，BSC
 * @returns {Promise<{true or false}>}
 */
export const checkChain = ({ target = '' }) => new Promise((resolve, reject) => {
  if (!window.ethereum) return;

  if (!target) {
    console.log('目标链不存在');
    reject();
    return;
  }
  const origin = sessionStorage.chainId;
  const targetId = chainIdMap[target];
  if (!targetId) {
    Message.error('请手动切换网络');
    reject();
    return;
  }
  if (origin === targetId) {
    resolve(true);
    return;
  }
  const netInfo = { BSC };
  if (!netInfo[target]) {
    Message.error('网络不支持');
    reject();
    return;
  }
  ethereum.request(netInfo[target]).then(res => {
    console.log(res);
    resolve(true);
  }).catch(err => {
    Message.error(`网络切换失败，请手动切换至${target}网`);
    reject(err);
  });
});

/**
 * 获取实例
 * @param abi 合约interFace
 * @param address 合约地址
 * @returns {Promise<Contract>}
 */
export const _getContractInstance = (abi, address) => new web3.eth.Contract(abi, address);

/**
 * 获取代币地址余额
 * @param abi 合约interFace
 * @param address 合约地址
 * @param account 账户地址
 * @param chain
 * @param currency
 * @returns {Promise<{symbol [币种], decimals [小数位], banlance [余额]}>}
 */
export const getBanlance = async ({ abi, address, account, chain, currency }) => {
  try {
    let [banlance, decimals, symbol] = ['', '', ''];
    if (currency === 'BNB' && chain === 'BSC') {
      banlance = await web3.eth.getBalance(account);
      decimals = 18;
      symbol = 'BNB';
    } else {
      const instance = _getContractInstance(abi, address);
      banlance = await instance.methods.balanceOf(account).call();
      decimals = await instance.methods.decimals().call();
      symbol = await instance.methods.symbol().call();
    }
    return {
      banlance: toDecimals(banlance, decimals),
      decimals,
      symbol,
    };
  } catch (e) {
    console.log('getBanlance', e);
    return {
      banlance: '',
      decimals: '',
      symbol: '',
    };
  }
};

/**
 * 连接MetaMask并选择账户 将账户地址返回
 * @returns {Promise<*>}
 */
export const getAccountForMetaMask = async () => {
  if (!window.ethereum) return;

  let requestInfo = [];
  await ethereum.request({
    method: 'eth_requestAccounts',
  })
    .then(async (acts) => {
      requestInfo = acts;
    })
    .catch((error) => {
      if (error.code === 4001) {
        console.log('Permissions needed to continue.');
      } else {
        console.log(error);
      }
      requestInfo = [''];
    });

  return requestInfo[0];
};

/**
 * 􏰄􏰂􏰃􏰆􏰄􏰂􏰃􏰆􏰄􏰂􏰃􏰆􏰄􏰂􏰃􏰆获取left in sales
 * @param abi
 * @param address
 * @returns {Promise<*>}
 */
export const getLeftSales = async (abi, address) => {
  const instance = _getContractInstance(abi, address);
  return toDecimals(await instance.methods.tokensAvailable().call(), 18);
};

/**
 * 􏰄􏰂􏰃􏰆􏰄􏰂􏰃􏰆􏰄􏰂􏰃􏰆􏰄􏰂􏰃􏰆判断是否是白名单地址
 * @param abi
 * @param address
 * @param amount
 * @returns {Promise<*>}
 */
export const isWhitelisted = async (abi, address, amount) => {
  const instance = _getContractInstance(abi, address);
  return instance.methods.isWhitelisted(amount).call();
};

/**
 * 购买
 * @returns {Promise<*>}
 */
const _transfer = async ({ from, to, amount }) => {
  const _amount = parseInt(toInteger(amount, 18).toString());
  try {
    await web3.eth.sendTransaction({ from, to, value: _amount, gas: web3.utils.toHex(100000) });
    return { type: 'success' };
  } catch (e) {
    console.log('_transfer error', e);
    return { type: 'failed' };
  }
};

/**
 * 兑换
 * @returns {Promise<void>}
 */
export const swap = async (params) => {
  try {
    return _transfer(params);
  } catch (ex) {
    return { type: 'failed' };
  }
};
